from flask import request, jsonify, g
from flask_jwt_extended import jwt_required, get_jwt_identity
import datetime
from bson import ObjectId

from app.api.v1 import api_bp
from app import mongo
from app.utils.auth import permission_required
from app.schemas.prescription import PrescriptionSchema, PrescriptionUpdateSchema, PrescriptionQuerySchema
from app.utils.common import normalize_data, paginate, generate_id

@api_bp.route('/prescriptions', methods=['GET'])
@jwt_required()
@permission_required('prescription:read')
def get_prescriptions():
    """获取处方列表"""
    page = request.args.get('page', 1, type=int)
    limit = request.args.get('limit', 20, type=int)
    sort_by = request.args.get('sortBy', 'createdAt')
    order = request.args.get('order', 'desc')
    
    # 构建查询条件
    query = {}
    
    # 按患者ID筛选
    patient_id = request.args.get('patientId')
    if patient_id:
        query['patientId'] = patient_id
    
    # 按医生ID筛选
    doctor_id = request.args.get('doctorId')
    if doctor_id:
        query['doctorId'] = doctor_id
    
    # 按科室ID筛选
    department_id = request.args.get('departmentId')
    if department_id:
        query['departmentId'] = department_id
    
    # 按医疗记录ID筛选
    medical_record_id = request.args.get('medicalRecordId')
    if medical_record_id:
        query['medicalRecordId'] = medical_record_id
    
    # 按状态筛选
    status = request.args.get('status')
    if status and status != 'all':
        query['status'] = status
    
    # 按日期范围筛选
    start_date = request.args.get('startDate')
    if start_date:
        try:
            start_date = datetime.datetime.strptime(start_date, '%Y-%m-%d')
            if 'visitDate' not in query:
                query['visitDate'] = {}
            query['visitDate']['$gte'] = start_date
        except ValueError:
            pass
    
    end_date = request.args.get('endDate')
    if end_date:
        try:
            end_date = datetime.datetime.strptime(end_date, '%Y-%m-%d')
            # 将结束日期设为当天的结束时间
            end_date = end_date.replace(hour=23, minute=59, second=59)
            if 'visitDate' not in query:
                query['visitDate'] = {}
            query['visitDate']['$lte'] = end_date
        except ValueError:
            pass
    
    # 确定排序
    sort_direction = -1 if order.lower() == 'desc' else 1
    
    # 获取数据
    prescriptions_cursor = mongo.db.prescriptions.find(query).sort(sort_by, sort_direction)
    
    # 分页
    paginated_data = paginate(prescriptions_cursor, page, limit)
    
    # 标准化数据并添加患者和医生信息
    prescriptions = []
    for prescription in paginated_data['items']:
        normalized_prescription = normalize_data(prescription)
        
        # 获取患者信息
        patient_name = ''
        if 'patientId' in prescription:
            patient_id = prescription['patientId']
            if isinstance(patient_id, str) and ObjectId.is_valid(patient_id):
                patient_id = ObjectId(patient_id)
            patient = mongo.db.patients.find_one({'_id': patient_id})
            if patient:
                patient_name = patient.get('name', '')
        normalized_prescription['patientName'] = patient_name
        
        # 获取医生信息
        doctor_name = ''
        if 'doctorId' in prescription:
            doctor_id = prescription['doctorId']
            if isinstance(doctor_id, str) and ObjectId.is_valid(doctor_id):
                doctor_id = ObjectId(doctor_id)
            doctor = mongo.db.doctors.find_one({'_id': doctor_id})
            if doctor:
                doctor_name = doctor.get('name', '')
        normalized_prescription['doctorName'] = doctor_name
        
        # 获取科室信息
        department_name = ''
        if 'departmentId' in prescription:
            dept_id = prescription['departmentId']
            if isinstance(dept_id, str) and ObjectId.is_valid(dept_id):
                dept_id = ObjectId(dept_id)
            department = mongo.db.departments.find_one({'_id': dept_id})
            if department:
                department_name = department.get('name', '')
        normalized_prescription['departmentName'] = department_name
        
        prescriptions.append(normalized_prescription)
    
    return jsonify({
        'success': True,
        'data': {
            'total': paginated_data['total'],
            'page': paginated_data['page'],
            'limit': paginated_data['per_page'],
            'prescriptions': prescriptions
        }
    }), 200

@api_bp.route('/prescriptions', methods=['POST'])
@jwt_required()
@permission_required('prescription:create')
def create_prescription():
    """创建新处方"""
    # 验证请求数据
    schema = PrescriptionSchema()
    errors = schema.validate(request.json)
    if errors:
        return jsonify({
            'success': False,
            'message': '请求数据验证失败',
            'errors': errors
        }), 400
    
    data = request.json
    
    # 验证患者是否存在
    patient_id = data.get('patientId')
    if not mongo.db.patients.find_one({'_id': ObjectId(patient_id)}):
        return jsonify({
            'success': False,
            'message': '患者不存在'
        }), 400
    
    # 验证医生是否存在
    doctor_id = data.get('doctorId')
    if not mongo.db.doctors.find_one({'_id': ObjectId(doctor_id)}):
        return jsonify({
            'success': False,
            'message': '医生不存在'
        }), 400
    
    # 验证科室是否存在
    department_id = data.get('departmentId')
    if not mongo.db.departments.find_one({'_id': ObjectId(department_id)}):
        return jsonify({
            'success': False,
            'message': '科室不存在'
        }), 400
    
    # 检查药品是否存在并计算总金额
    total_amount = 0
    drug_items = []
    
    for item in data.get('items', []):
        drug_id = item.get('drugId')
        if not ObjectId.is_valid(drug_id):
            return jsonify({
                'success': False,
                'message': f'药品ID无效: {drug_id}'
            }), 400
        
        drug = mongo.db.drugs.find_one({'_id': ObjectId(drug_id)})
        if not drug:
            return jsonify({
                'success': False,
                'message': f'药品不存在: {drug_id}'
            }), 400
        
        # 添加药品信息
        item['drugName'] = drug.get('name', '')
        item['specification'] = drug.get('specification', '')
        
        # 计算金额
        price = drug.get('price', 0)
        quantity = item.get('quantity', 0)
        total_amount += price * quantity
        
        drug_items.append(item)
    
    # 更新药品列表和总金额
    data['items'] = drug_items
    data['totalAmount'] = total_amount
    
    # 生成处方ID
    data['prescriptionId'] = generate_id('RX')
    
    # 设置创建时间和更新时间
    now = datetime.datetime.utcnow()
    data['createdAt'] = now
    data['updatedAt'] = now
    
    # 保存到数据库
    result = mongo.db.prescriptions.insert_one(data)
    
    # 获取相关信息用于返回
    patient = mongo.db.patients.find_one({'_id': ObjectId(patient_id)})
    patient_name = patient.get('name', '') if patient else ''
    
    return jsonify({
        'success': True,
        'message': '处方创建成功',
        'data': {
            'id': str(result.inserted_id),
            'prescriptionId': data['prescriptionId'],
            'patientName': patient_name,
            'visitDate': data['visitDate'].isoformat() if isinstance(data['visitDate'], datetime.datetime) else data['visitDate'],
            'status': data['status'],
            'totalAmount': data['totalAmount'],
            'createdAt': now.isoformat()
        }
    }), 201

@api_bp.route('/prescriptions/<id>', methods=['GET'])
@jwt_required()
@permission_required('prescription:read')
def get_prescription(id):
    """获取单个处方详情"""
    # 尝试按ID查找
    prescription = None
    
    # 如果是有效的ObjectId，按_id查找
    if ObjectId.is_valid(id):
        prescription = mongo.db.prescriptions.find_one({'_id': ObjectId(id)})
    
    # 如果没找到，尝试按prescriptionId查找
    if not prescription:
        prescription = mongo.db.prescriptions.find_one({'prescriptionId': id})
    
    if not prescription:
        return jsonify({
            'success': False,
            'message': '处方不存在'
        }), 404
    
    # 标准化处方数据
    normalized_prescription = normalize_data(prescription)
    
    # 获取患者信息
    patient_info = None
    if 'patientId' in prescription:
        patient_id = prescription['patientId']
        if isinstance(patient_id, str) and ObjectId.is_valid(patient_id):
            patient_id = ObjectId(patient_id)
        patient = mongo.db.patients.find_one({'_id': patient_id})
        if patient:
            patient_info = {
                'id': str(patient['_id']),
                'patientId': patient.get('patientId', ''),
                'name': patient.get('name', ''),
                'gender': patient.get('gender', ''),
                'age': calculate_age(patient.get('birthDate')),
                'idNumber': patient.get('idNumber', ''),
                'phone': patient.get('contactInfo', {}).get('phone', '')
            }
    
    # 获取医生信息
    doctor_info = None
    doctor_name = ''
    if 'doctorId' in prescription:
        doctor_id = prescription['doctorId']
        if isinstance(doctor_id, str) and ObjectId.is_valid(doctor_id):
            doctor_id = ObjectId(doctor_id)
        doctor = mongo.db.doctors.find_one({'_id': doctor_id})
        if doctor:
            doctor_info = {
                'id': str(doctor['_id']),
                'staffId': doctor.get('staffId', ''),
                'name': doctor.get('name', ''),
                'title': doctor.get('title', '')
            }
            doctor_name = doctor.get('name', '')
    
    # 获取科室信息
    department_info = None
    department_name = ''
    if 'departmentId' in prescription:
        dept_id = prescription['departmentId']
        if isinstance(dept_id, str) and ObjectId.is_valid(dept_id):
            dept_id = ObjectId(dept_id)
        department = mongo.db.departments.find_one({'_id': dept_id})
        if department:
            department_info = {
                'id': str(department['_id']),
                'name': department.get('name', ''),
                'location': department.get('location', '')
            }
            department_name = department.get('name', '')
    
    # 获取审核人和发药人信息
    audit_info = None
    if 'auditBy' in prescription and prescription['auditBy']:
        audit_id = prescription['auditBy']
        if isinstance(audit_id, str) and ObjectId.is_valid(audit_id):
            audit_id = ObjectId(audit_id)
        auditor = mongo.db.users.find_one({'_id': audit_id})
        if auditor:
            audit_info = {
                'id': str(auditor['_id']),
                'name': auditor.get('name', ''),
                'role': auditor.get('role', '')
            }
    
    dispensed_info = None
    if 'dispensedBy' in prescription and prescription['dispensedBy']:
        dispense_id = prescription['dispensedBy']
        if isinstance(dispense_id, str) and ObjectId.is_valid(dispense_id):
            dispense_id = ObjectId(dispense_id)
        dispenser = mongo.db.users.find_one({'_id': dispense_id})
        if dispenser:
            dispensed_info = {
                'id': str(dispenser['_id']),
                'name': dispenser.get('name', ''),
                'role': dispenser.get('role', '')
            }
    
    # 添加相关信息到处方中
    normalized_prescription['patientInfo'] = patient_info
    normalized_prescription['doctorInfo'] = doctor_info
    normalized_prescription['departmentInfo'] = department_info
    normalized_prescription['auditInfo'] = audit_info
    normalized_prescription['dispensedInfo'] = dispensed_info
    
    # 添加医生、科室和患者名称到处方数据中
    normalized_prescription['doctorName'] = doctor_name
    normalized_prescription['departmentName'] = department_name
    normalized_prescription['patientName'] = patient_info.get('name', '') if patient_info else ''
    
    return jsonify({
        'success': True,
        'data': normalized_prescription
    }), 200

@api_bp.route('/prescriptions/<id>', methods=['PUT'])
@jwt_required()
@permission_required('prescription:update')
def update_prescription(id):
    """更新处方"""
    # 验证请求数据
    schema = PrescriptionUpdateSchema()
    errors = schema.validate(request.json)
    if errors:
        return jsonify({
            'success': False,
            'message': '请求数据验证失败',
            'errors': errors
        }), 400
    
    data = request.json
    
    # 查找处方
    prescription = None
    if ObjectId.is_valid(id):
        prescription = mongo.db.prescriptions.find_one({'_id': ObjectId(id)})
    
    if not prescription:
        prescription = mongo.db.prescriptions.find_one({'prescriptionId': id})
    
    if not prescription:
        return jsonify({
            'success': False,
            'message': '处方不存在'
        }), 404
    
    # 如果处方已发药，不允许修改
    if prescription.get('status') == '已发药':
        return jsonify({
            'success': False,
            'message': '已发药的处方不允许修改'
        }), 403
    
    # 准备更新数据
    update_data = data.copy()
    update_data['updatedAt'] = datetime.datetime.utcnow()
    
    # 如果状态变更为审核，添加审核信息
    if 'status' in data and data['status'] == '已审核' and prescription.get('status') != '已审核':
        current_user_id = get_jwt_identity()
        update_data['auditBy'] = current_user_id
        update_data['auditTime'] = datetime.datetime.utcnow()
    
    # 如果状态变更为发药，添加发药信息
    if 'status' in data and data['status'] == '已发药' and prescription.get('status') != '已发药':
        current_user_id = get_jwt_identity()
        update_data['dispensedBy'] = current_user_id
        update_data['dispensedTime'] = datetime.datetime.utcnow()
        
        # 如果状态变为已发药，需要更新药品库存
        if prescription.get('status') != '已发药':
            # 扣减药品库存
            for item in prescription.get('items', []):
                drug_id = item.get('drugId')
                quantity = item.get('quantity', 0)
                
                if drug_id and quantity > 0:
                    # 获取可用库存记录，按过期日期排序
                    inventory_records = list(mongo.db.drug_inventory.find(
                        {'drugId': drug_id, 'quantity': {'$gt': 0}, 'status': {'$nin': ['过期']}}
                    ).sort('expirationDate', 1))
                    
                    # 逐条扣减库存
                    remaining_quantity = quantity
                    for record in inventory_records:
                        available = record.get('quantity', 0)
                        if available <= 0:
                            continue
                        
                        deduct = min(available, remaining_quantity)
                        remaining_quantity -= deduct
                        
                        # 更新库存记录
                        mongo.db.drug_inventory.update_one(
                            {'_id': record['_id']},
                            {'$set': {'quantity': available - deduct, 'updatedAt': datetime.datetime.utcnow()}}
                        )
                        
                        if remaining_quantity <= 0:
                            break
                    
                    # 如果库存不足，记录警告信息
                    if remaining_quantity > 0:
                        if 'warnings' not in update_data:
                            update_data['warnings'] = []
                        update_data['warnings'].append(f"药品'{item.get('drugName', drug_id)}'库存不足，缺少{remaining_quantity}个单位")
    
    # 更新数据库
    result = mongo.db.prescriptions.update_one(
        {'_id': prescription['_id']},
        {'$set': update_data}
    )
    
    if result.modified_count == 0:
        return jsonify({
            'success': False,
            'message': '处方更新失败'
        }), 500
    
    return jsonify({
        'success': True,
        'message': '处方更新成功',
        'data': {
            'id': str(prescription['_id']),
            'prescriptionId': prescription['prescriptionId'],
            'status': data.get('status', prescription.get('status')),
            'updatedAt': update_data['updatedAt'].isoformat()
        }
    }), 200

@api_bp.route('/prescriptions/<id>/audit', methods=['POST'])
@jwt_required()
@permission_required('prescription:audit')
def audit_prescription(id):
    """审核处方"""
    # 查找处方
    prescription = None
    if ObjectId.is_valid(id):
        prescription = mongo.db.prescriptions.find_one({'_id': ObjectId(id)})
    
    if not prescription:
        prescription = mongo.db.prescriptions.find_one({'prescriptionId': id})
    
    if not prescription:
        return jsonify({
            'success': False,
            'message': '处方不存在'
        }), 404
    
    # 检查处方状态
    if prescription.get('status') != '待审核':
        return jsonify({
            'success': False,
            'message': f"处方当前状态为'{prescription.get('status')}',无法进行审核"
        }), 400
    
    # 准备更新数据
    current_user_id = get_jwt_identity()
    now = datetime.datetime.utcnow()
    
    update_data = {
        'status': '已审核',
        'auditBy': current_user_id,
        'auditTime': now,
        'updatedAt': now
    }
    
    # 如果有备注信息
    remarks = request.json.get('remarks')
    if remarks:
        update_data['remarks'] = remarks
    
    # 更新数据库
    result = mongo.db.prescriptions.update_one(
        {'_id': prescription['_id']},
        {'$set': update_data}
    )
    
    if result.modified_count == 0:
        return jsonify({
            'success': False,
            'message': '处方审核失败'
        }), 500
    
    # 获取审核人信息
    auditor = mongo.db.users.find_one({'_id': ObjectId(current_user_id)})
    auditor_name = auditor.get('name', '') if auditor else '未知'
    
    # 审核通过后自动创建支付记录
    try:
        # 计算处方总金额
        total_amount = prescription.get('totalAmount', 0)
        
        # 创建支付记录数据
        payment_data = {
            'paymentId': generate_id('P'),
            'patientId': prescription.get('patientId'),
            'relatedType': 'prescription',
            'relatedId': str(prescription['_id']),
            'amount': total_amount,
            'totalAmount': total_amount,
            'status': '待支付',
            'items': [],
            'createdAt': now,
            'updatedAt': now
        }
        
        # 添加药品明细到支付记录
        for item in prescription.get('items', []):
            payment_data['items'].append({
                'type': 'prescription',
                'itemId': str(prescription['_id']),
                'amount': item.get('amount', 0)
            })
        
        # 如果处方关联了科室信息，添加到支付记录
        if 'departmentId' in prescription:
            payment_data['departmentId'] = prescription.get('departmentId')
        
        # 保存支付记录
        mongo.db.payments.insert_one(payment_data)
    except Exception as e:
        # 记录错误但不影响处方审核结果
        print(f"创建处方支付记录时出错: {str(e)}")
    
    return jsonify({
        'success': True,
        'message': '处方审核成功',
        'data': {
            'id': str(prescription['_id']),
            'prescriptionId': prescription['prescriptionId'],
            'status': '已审核',
            'auditorName': auditor_name,
            'auditTime': now.isoformat()
        }
    }), 200

@api_bp.route('/prescriptions/<id>/dispense', methods=['POST'])
@jwt_required()
@permission_required('prescription:dispense')
def dispense_prescription(id):
    """发药"""
    # 查找处方
    prescription = None
    if ObjectId.is_valid(id):
        prescription = mongo.db.prescriptions.find_one({'_id': ObjectId(id)})
    
    if not prescription:
        prescription = mongo.db.prescriptions.find_one({'prescriptionId': id})
    
    if not prescription:
        return jsonify({
            'success': False,
            'message': '处方不存在'
        }), 404
    
    # 检查处方状态
    if prescription.get('status') != '已审核':
        return jsonify({
            'success': False,
            'message': f"处方当前状态为'{prescription.get('status')}',无法进行发药"
        }), 400
    
    # 准备更新数据
    current_user_id = get_jwt_identity()
    now = datetime.datetime.utcnow()
    
    update_data = {
        'status': '已发药',
        'dispensedBy': current_user_id,
        'dispensedTime': now,
        'updatedAt': now
    }
    
    # 如果有备注信息
    remarks = request.json.get('remarks')
    if remarks:
        update_data['remarks'] = remarks
    
    # 扣减药品库存
    warnings = []
    for item in prescription.get('items', []):
        drug_id = item.get('drugId')
        quantity = item.get('quantity', 0)
        
        if drug_id and quantity > 0:
            # 获取可用库存记录，按过期日期排序
            inventory_records = list(mongo.db.drug_inventory.find(
                {'drugId': drug_id, 'quantity': {'$gt': 0}, 'status': {'$nin': ['过期']}}
            ).sort('expirationDate', 1))
            
            # 逐条扣减库存
            remaining_quantity = quantity
            for record in inventory_records:
                available = record.get('quantity', 0)
                if available <= 0:
                    continue
                
                deduct = min(available, remaining_quantity)
                remaining_quantity -= deduct
                
                # 更新库存记录
                mongo.db.drug_inventory.update_one(
                    {'_id': record['_id']},
                    {'$set': {'quantity': available - deduct, 'updatedAt': now}}
                )
                
                if remaining_quantity <= 0:
                    break
            
            # 如果库存不足，记录警告信息
            if remaining_quantity > 0:
                warnings.append(f"药品'{item.get('drugName', drug_id)}'库存不足，缺少{remaining_quantity}个单位")
    
    # 如果有警告信息，添加到更新数据中
    if warnings:
        update_data['warnings'] = warnings
    
    # 更新数据库
    result = mongo.db.prescriptions.update_one(
        {'_id': prescription['_id']},
        {'$set': update_data}
    )
    
    if result.modified_count == 0:
        return jsonify({
            'success': False,
            'message': '处方发药失败'
        }), 500
    
    # 获取发药人信息
    dispenser = mongo.db.users.find_one({'_id': ObjectId(current_user_id)})
    dispenser_name = dispenser.get('name', '') if dispenser else '未知'
    
    return jsonify({
        'success': True,
        'message': '处方发药成功',
        'data': {
            'id': str(prescription['_id']),
            'prescriptionId': prescription['prescriptionId'],
            'status': '已发药',
            'dispenserName': dispenser_name,
            'dispensedTime': now.isoformat(),
            'warnings': warnings
        }
    }), 200

@api_bp.route('/prescriptions/<id>/cancel', methods=['POST'])
@jwt_required()
@permission_required('prescription:update')
def cancel_prescription(id):
    """取消处方"""
    # 查找处方
    prescription = None
    if ObjectId.is_valid(id):
        prescription = mongo.db.prescriptions.find_one({'_id': ObjectId(id)})
    
    if not prescription:
        prescription = mongo.db.prescriptions.find_one({'prescriptionId': id})
    
    if not prescription:
        return jsonify({
            'success': False,
            'message': '处方不存在'
        }), 404
    
    # 检查处方状态
    if prescription.get('status') == '已发药':
        return jsonify({
            'success': False,
            'message': '已发药的处方不能取消'
        }), 400
    
    # 准备更新数据
    now = datetime.datetime.utcnow()
    
    update_data = {
        'status': '已取消',
        'updatedAt': now
    }
    
    # 如果有取消原因
    reason = request.json.get('reason')
    if reason:
        update_data['cancelReason'] = reason
    
    # 更新数据库
    result = mongo.db.prescriptions.update_one(
        {'_id': prescription['_id']},
        {'$set': update_data}
    )
    
    if result.modified_count == 0:
        return jsonify({
            'success': False,
            'message': '处方取消失败'
        }), 500
    
    return jsonify({
        'success': True,
        'message': '处方取消成功',
        'data': {
            'id': str(prescription['_id']),
            'prescriptionId': prescription['prescriptionId'],
            'status': '已取消',
            'updatedAt': now.isoformat()
        }
    }), 200

def calculate_age(birth_date):
    """计算年龄"""
    if not birth_date:
        return None
    
    if isinstance(birth_date, str):
        try:
            birth_date = datetime.datetime.strptime(birth_date, '%Y-%m-%d')
        except ValueError:
            return None
    
    today = datetime.date.today()
    age = today.year - birth_date.year - ((today.month, today.day) < (birth_date.month, birth_date.day))
    return age 